#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/epoll.h>

#include "server_socket.c"

#define SERVERPORT 3333 
#define MAX_LINE 1024
#define FD_INIT_SIZE 128

// 用户态缓冲区，用于存储服务端需要发送的数据 
// 采用非阻塞写的话，数据一次性不一定发的完，
// 所以先存储在用户态缓冲区中
struct Buffer {
    int connect_fd;  // 客户端连接 socket 文件描述符
    char buffer[MAX_LINE];  //实际存储数据的缓冲区
	// buffer 中：
	// [0...readIndex) 区间数据已经写到客户端
	// [readIndex...writeIndex) 区间数据还未写到客户端
	// [writeIndex...MAX_LINE) 区间还未接收客户端的数据
    size_t writeIndex;    
    size_t readIndex;  
    int readable;           //是否可以读
};

// 初始化一个用户态缓冲区
struct Buffer *alloc_Buffer() {
    struct Buffer *buffer = malloc(sizeof(struct Buffer));
    if (!buffer)
        return NULL;
    buffer->connect_fd = 0;
    buffer->writeIndex = buffer->readIndex = buffer->readable = 0;
    return buffer;
}

// 释放指定缓冲区的内存
void free_Buffer(struct Buffer *buffer) {
    free(buffer);
}

// 字母大小写转换 
char process_char(char c) {
    if (c >= 'a' && c <= 'z') {
        return c - 32;
    } else if (c >= 'A' && c <= 'Z') {
        return c + 32;
    }
    return c;
}

int onSocketRead(int fd, struct Buffer *buffer) {
    char buf[1024];
    int i;
    ssize_t result;
    while (1) {
		// 非阻塞读取客户端数据到 buf 中
        result = read(fd, buf, sizeof(buf));
		// 没有读到数据，直接退出
        if (result <= 0)
            break;
		
		// 将读到的数据处理后，放到用户态缓冲区
        for (i = 0; i < result; ++i) {
            if (buffer->writeIndex < sizeof(buffer->buffer))
                buffer->buffer[buffer->writeIndex++] = process_char(buf[i]);
            if (buf[i] == '\n') {
                buffer->readable = 1;  //缓冲区可以读
            }
        }
    }
	
    if (result == 0) { // FIN 报文，调用方需要关闭当前连接 socket
        return 1;
    } else if (result < 0) {
        if (errno == EAGAIN) // 没有数据可读
            return 0;
		// 读的时候出错了
        return -1;
    }

    return 0;
}

int onSocketWrite(int fd, struct Buffer *buffer) {
    while (buffer->readIndex < buffer->writeIndex) {
        ssize_t result = write(fd, 
				buffer->buffer + buffer->readIndex, // 可写数据的起始位置
				buffer->writeIndex - buffer->readIndex); // 可写数据的长度
        
		if (result < 0) {
            if (errno == EAGAIN) // 发送内核态缓冲区没有空闲的地方
                return 0;
            return -1;
        }
		
		// 写完了 result 个字节
        buffer->readIndex += result;
    }
	
	// 没有可以写的数据了
    if (buffer->readIndex == buffer->writeIndex)
        buffer->readIndex = buffer->writeIndex = 0;

    buffer->readable = 0;

    return 0;
}

int main() {
    struct sockaddr_in cs;
    int a_size, i;
    int listen_socket_fd; 
	
	// 创建一个监听 socket
	listen_socket_fd = tcp_listen_socket(SERVERPORT);

	// 设置监听 socket 的 IO 为非阻塞 IO
	fcntl(listen_socket_fd, F_SETFL, O_NONBLOCK);
	
	// 初始化所有客户端连接 socket 缓存数据的缓冲区(用户态)
	struct Buffer *buffer[FD_INIT_SIZE];
    for (i = 0; i < FD_INIT_SIZE; ++i) {
        buffer[i] = alloc_Buffer();
    }	
	
	int retval;
	int efd;
    struct epoll_event event;
    struct epoll_event *events;
	// ① 创建 epoll 实例
	efd = epoll_create(10);
    if (efd == -1) {
        perror("epoll create failed");
    }
	
	// ② 添加感兴趣的 fd 及其事件到 epoll 实例中
	// 添加监听 socket 的可读事件
	event.data.fd = listen_socket_fd;
    event.events = EPOLLIN;
    if (epoll_ctl(efd, EPOLL_CTL_ADD, listen_socket_fd, &event) == -1) {
        perror("epoll_ctl add listen fd failed");
    }
	
	events = calloc(FD_INIT_SIZE, sizeof(event));

	for (;;) {
		// ③ 在等待内核 I/O 事件的分发。
		retval = epoll_wait(efd, events, FD_INIT_SIZE, -1);
		if (retval < 0) {
			perror("select error");
		}

		printf("epoll_wait wakeup \n");

		// 处理 retval 个 I/O 事件
		for (i = 0; i < retval; i++) {
			// 判断监听 socket 是否有连接进来（可读事件发生）
			if (events[i].data.fd == listen_socket_fd) {
				int fd = accept(listen_socket_fd, (struct sockaddr*)&cs, &a_size);
    			if(fd == -1) {
        			perror("accept");
        			exit(1);
    			} else if (fd > FD_INIT_SIZE) { 
					// 大于服务器同时支持的最大的 socket 连接
					perror("too many connections");
					close(fd);
				} else {
    				printf("accept success! fd = %d\n", fd);
					// 将当前连接进来的 socket 设置为非阻塞
					fcntl(fd, F_SETFL, O_NONBLOCK);
					// 添加客户端连接 socket 可读事件到 epoll 中 
					event.data.fd = fd;
					// 默认是 level-triggered（条件触发）
					// EPOLLET：设置为 edge-triggered（边缘触发）
				    event.events = EPOLLIN | EPOLLET;
    				if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &event) == -1) {
        				perror("epoll_ctl add listen fd failed");
    				}
				}
			} else { 
            	int r = 0;
				// 处理每个客户端连接 socket 的事件
				int currfd = events[i].data.fd;
			
				// 处理客户端连接 socket 可读事件
            	if (events[i].events & EPOLLIN) {
                	// r = onSocketRead(currfd, buffer[currfd]);
                	printf("get EPOLLIN event on socket fd == %d\n", currfd);
            	}
				// 处理当前连接 socket 可写事件
            	if (r == 0 && events[i].events & EPOLLOUT) {
                	r = onSocketWrite(currfd, buffer[currfd]);
					// 如果没有数据可以处理，则注销掉可写事件
					if (!buffer[currfd]->readable) {
						event.data.fd = currfd;
                        event.events = EPOLLIN;
                        if (epoll_ctl(efd, EPOLL_CTL_MOD, currfd, &event) == -1) {
                            perror("epoll_ctl mod curr fd failed");
                        }
					}
            	}
            	if (r) { // 返回 1 的话，表示收到 FIN 报文，关闭连接
					// 从 epoll 中删除这个 fd
                    if (epoll_ctl(efd, EPOLL_CTL_DEL, currfd, &event) == -1) {
                        perror("epoll_ctl mov curr fd failed");
                    }
                	close(currfd);
            	}
        	}
		}
	}
	// 关闭服务端 server socket
    close(listen_socket_fd);
}
